package activity

import (
	"context"
	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/resultx"
	enum "mall/service/backend/common/enum/promotion"
	"mall/service/backend/common/utils/pointy"
	"mall/service/promotion/model"
	"mall/service/promotion/rpc/internal/svc"
	"mall/service/promotion/rpc/types/promotion"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetActivityListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetActivityListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetActivityListLogic {
	return &GetActivityListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetActivityListLogic) GetActivityList(in *promotion.BaseListReq) (*promotion.ActivityListResp, error) {
	// logrus.Info(fmt.Sprintf("GetActivityList BaseListReq: %+v", in))
	// Limit:10 Preload:"activity:Id,Name,Desc,Members,StartedAt,EndedAt" Filter:"Status,equalTo:10" PlatformId:3

	if in.Filter == nil || len(*in.Filter) == 0 {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)

	// logrus.Info(fmt.Sprintf("GetActivityList preloadMap: %+v", preloadMap))
	// map[activity:[Id Name Desc Members StartedAt EndedAt]]
	// logrus.Info(fmt.Sprintf("GetActivityList eagerLoadMap: %+v", eagerLoadMap))
	// map[activity:[ruleGroup]]

	promotionActivityEntityName := model.RpcEntityNames.PromotionActivity
	if _, ok := model.RpcEntityPreloadMap[promotionActivityEntityName]; !ok {
		return &promotion.ActivityListResp{}, nil
	}

	promotionActivityRepositoryName := model.RepositoryNames.PromotionActivity
	columnMap, ok := model.RepositoryPreloadMap[promotionActivityRepositoryName]
	if !ok {
		return &promotion.ActivityListResp{}, nil
	}

	var selectCols []string
	if preloadFields, ok := preloadMap[promotionActivityEntityName]; ok {
		selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
	}

	filterMap := modelx.ParseFilter(in.Filter, columnMap)
	// logrus.Info(fmt.Sprintf("GetActivityList filterMap: %+v", filterMap))
	// map[status:map[equalTo:[10]]]
	if filterMap == nil {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	orderBy := modelx.ParseSorter(in.Sorter, columnMap)
	// logrus.Info(fmt.Sprintf("GetActivityList orderBy: %s", orderBy))
	// sort DESC,ID DESC

	res, count, err := l.svcCtx.Activity.GetList(l.ctx, model.M{
		"offset": in.Offset,
		"limit":  in.Limit,
		// "search":  in.Search,
		"orderBy": orderBy,
		"select":  strings.Join(selectCols, ","),
	}, 2, filterMap)
	if err != nil {
		return nil, err
	}

	hasNextPage, hasPreviousPage := modelx.ParseCount(count)
	resp := &promotion.ActivityListResp{
		HasNextPage:     &hasNextPage,
		HasPreviousPage: &hasPreviousPage,
	}

	if len(res) > 0 {
		idGroupModeMap := make(map[uint64]uint8)
		var ids []any
		for _, v := range res {
			ids = append(ids, v.ID)
			idGroupModeMap[v.ID] = v.GroupMode
		}

		logTotalMap := make(map[uint64]uint64)
		subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
		if eagerLoadEntities, ok := eagerLoadMap[promotionActivityEntityName]; ok {
			for _, entity := range eagerLoadEntities {
				if entity == "logTotal" {
					if in.VisitorId != nil && *in.VisitorId > 0 {
						logFilterMap := make(map[string]map[string][]any)
						logFilterMap[model.PromotionActivityLogColumns.ActivityID] = map[string][]any{
							"in": ids,
						}
						logFilterMap[model.PromotionActivityLogColumns.UserID] = map[string][]any{
							"equalTo": {*in.VisitorId},
						}
						logFilterMap[model.PromotionActivityLogColumns.Type] = map[string][]any{
							"equalTo": {globalkey.ActivityOprTypeParticipate},
						}
						logFilterMap[model.PromotionActivityLogColumns.Status] = map[string][]any{
							"equalTo": {globalkey.StatusEnabled},
						}
						list, _, err := l.svcCtx.Activity.GetLogList(l.ctx, model.M{}, 5, logFilterMap)
						if err != nil {
							return nil, err
						}

						if len(list) > 0 {
							for _, v := range list {
								logTotalMap[v.ActivityID] = v.OrderID
							}
						}
					}
					continue
				}

				if entitySettingMap, ok := model.RpcEntityPreloadMap[entity]; ok {
					subEntitySettingMap[entity] = entitySettingMap
				}
			}
		}

		idGroupMap := make(map[uint64][]*promotion.ActivityRuleGroupInfo)
		ruleGroupEntityName := model.RpcEntityNames.PromotionRuleGroup
		if _, ok := subEntitySettingMap[ruleGroupEntityName]; ok {
			ruleGroupRepositoryName := model.RepositoryNames.PromotionRuleGroup
			subPreloadFields, hasSubPreloadFields := preloadMap[ruleGroupEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[ruleGroupRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				groupFilterMap := make(map[string]map[string][]any)
				groupFilterMap[model.PromotionRuleGroupColumns.ActivityID] = map[string][]any{
					"in": ids,
				}
				groupFilterMap[model.PromotionRuleGroupColumns.Status] = map[string][]any{
					"equalTo": {globalkey.StatusEnabled},
				}
				groups, _, err := l.svcCtx.Activity.GetRuleGroupList(l.ctx, model.M{
					"orderBy": model.PromotionRuleGroupColumns.Sort,
					"select":  strings.Join(subSelectCols, ","),
				}, -1, groupFilterMap)
				if err != nil {
					return nil, err
				}

				if len(groups) > 0 {
					var groupIds []any
					for _, v := range groups {
						groupIds = append(groupIds, v.GroupID)
					}

					ruleFilterMap := make(map[string]map[string][]any)
					ruleFilterMap[model.PromotionRuleColumns.ActivityID] = map[string][]any{
						"in": ids,
					}
					ruleFilterMap[model.PromotionRuleColumns.GroupID] = map[string][]any{
						"in": groupIds,
					}
					ruleFilterMap[model.PromotionRuleColumns.Status] = map[string][]any{
						"equalTo": {globalkey.StatusEnabled},
					}
					rules, _, err := l.svcCtx.Activity.GetRuleList(l.ctx, model.M{
						"orderBy": model.PromotionRuleColumns.Sort,
					}, -1, ruleFilterMap)
					if err != nil {
						return nil, err
					}

					groupRuleMap := make(map[uint64][]*promotion.ActivityRuleInfo)
					if len(rules) > 0 {
						for _, v := range rules {
							var regions *string
							var value string
							switch v.RuleType {
							case enum.PromotionActivityRuleTypeDiscount:
								switch v.Mode {
								case enum.PromotionActivityRuleModeAmount, enum.PromotionActivityRuleModeFixed:
									value = moneyx.FormatAmount(int64(v.Value))
								case enum.PromotionActivityRuleModeDiscount:
									value = strconv.FormatInt(int64(v.Value), 10)
								}
							case enum.PromotionActivityRuleTypeFreeShipping:
								if v.Regions.Valid {
									regions = pointy.GetPointer(string(v.Regions.JSON))
								}
							case enum.PromotionActivityRuleTypeExtraPoint:
								value = strconv.FormatUint(v.Value, 10)
							case enum.PromotionActivityRuleTypeCoupon:
								value = strconv.FormatUint(v.Value, 10)
							}

							groupRuleMap[v.GroupID] = append(groupRuleMap[v.GroupID], &promotion.ActivityRuleInfo{
								Id:         &v.RuleID,
								ActivityId: &v.ActivityID,
								GroupId:    &v.GroupID,
								RuleType:   pointy.GetPointer(uint32(v.RuleType)),
								Regions:    regions,
								Mode:       pointy.GetPointer(uint32(v.Mode)),
								Value:      &value,
							})
						}
					}

					for _, v := range groups {
						if groupMode, ok := idGroupModeMap[v.ActivityID]; ok {
							if rs, ok := groupRuleMap[v.GroupID]; ok {
								var threshold string
								switch groupMode {
								case enum.PromotionActivityRuleModeAmount:
									threshold = moneyx.FormatAmount(int64(v.Threshhold))
								case enum.PromotionActivityRuleModeDiscount:
									threshold = strconv.FormatUint(v.Threshhold, 10)
								}

								idGroupMap[v.ActivityID] = append(idGroupMap[v.ActivityID], &promotion.ActivityRuleGroupInfo{
									Id:         &v.GroupID,
									ActivityId: &v.ActivityID,
									Threshold:  &threshold,
									Rules:      rs,
								})
							}
						}
					}
				}
			}
		}

		for _, v := range res {
			var groups []*promotion.ActivityRuleGroupInfo
			if gs, ok := idGroupMap[v.ID]; ok {
				groups = gs
			}
			var logTotal uint32
			if cnt, ok := logTotalMap[v.ID]; ok {
				logTotal = uint32(cnt)
			}
			resp.List = append(resp.List, &promotion.ActivityInfo{
				Id:                    &v.ID,
				Name:                  &v.Name,
				Description:           &v.Description,
				MemberRestriction:     &v.MemberRestriction,
				ActivityType:          pointy.GetPointer(uint32(v.ActivityType)),
				MutexType:             pointy.GetPointer(uint32(v.MutexType)),
				ScopeType:             pointy.GetPointer(uint32(v.ScopeType)),
				TimesLimit:            pointy.GetPointer(uint32(v.TimesLimit)),
				GroupMode:             pointy.GetPointer(uint32(v.GroupMode)),
				GroupType:             pointy.GetPointer(uint32(v.GroupType)),
				SeckillLimit:          pointy.GetPointer(uint32(v.SeckillLimit)),
				SeckillCancelDuration: pointy.GetPointer(uint32(v.SeckillCancelDuration)),
				SeckillNotifyDuration: pointy.GetPointer(uint32(v.SeckillNotifyDuration)),
				PackageType:           pointy.GetPointer(uint32(v.PackageType)),
				PackagePicId:          &v.PackagePicID,
				PackagePicUrl:         &v.PackagePicURL,
				Status:                pointy.GetPointer(uint32(v.Status)),
				StartedAt:             pointy.GetPointer(modelx.FormatNullDotTime(v.StartedAt, "")),
				EndedAt:               pointy.GetPointer(modelx.FormatNullDotTime(v.EndedAt, "")),
				LogTotal:              pointy.GetPointer(logTotal),
				Groups:                groups,
			})
		}
	}

	return resp, nil
}
